package com.example.demo.service.impl;

import com.example.demo.entity.Consultant;
import com.example.demo.entity.Supervisor;
import com.example.demo.entity.relation.ConsultRecord;
import com.example.demo.entity.relation.SupervisorBind;
import com.example.demo.exception.EntityAlreadyExistException;
import com.example.demo.exception.EntityNotExistException;
import com.example.demo.redis.RedisKey;
import com.example.demo.repository.dao.ConsultantDao;
import com.example.demo.repository.dao.SupervisorDao;
import com.example.demo.repository.dao.relation.ConsultRecordDao;
import com.example.demo.repository.dao.relation.SupervisorBindDao;
import com.example.demo.service.ConsultantService;
import com.example.demo.utils.JPAUpdateUtil;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.transaction.Transactional;
import java.util.*;

@Service
@Transactional
public class ConsultantServiceImpl implements ConsultantService {
    private final ConsultantDao consultantDao;
    private final ConsultRecordDao consultRecordDao;
    private final SupervisorBindDao supervisorBindDao;
    private final SupervisorDao supervisorDao;
    private final RedisTemplate<String, Object> redisTemplate;

    public ConsultantServiceImpl(ConsultantDao consultantDao, ConsultRecordDao consultRecordDao,
                                 SupervisorBindDao supervisorBindDao, SupervisorDao supervisorDao,
                                 RedisTemplate<String, Object> redisTemplate) {
        this.consultantDao = consultantDao;
        this.consultRecordDao = consultRecordDao;
        this.supervisorBindDao = supervisorBindDao;
        this.supervisorDao = supervisorDao;
        this.redisTemplate = redisTemplate;
    }

    @Override
    public String addConsultant(Consultant consultant) throws EntityAlreadyExistException {
        String id = consultant.getId();
        Optional<Consultant> origin = consultantDao.findById(id);
        if (origin.isPresent()) {
            throw new EntityAlreadyExistException("Consultant 实体已经存在");
        } else {
            consultantDao.save(consultant);
        }

        return consultant.getPhoneNumber();
    }

    @Override
    public void deleteConsultant(String id) {
        consultantDao.deleteById(id);
    }

    @Override
    public void deleteConsultants(List<String> ids) {
        for (String id : ids) {
            consultantDao.deleteById(id);
        }
    }

    @Override
    public void updateConsultant(String id, Consultant consultant) throws EntityNotExistException {
        Optional<Consultant> origin = consultantDao.findById(id);
        if (origin.isPresent()) {
            Consultant old = origin.get();
            JPAUpdateUtil.copyNullProperties(consultant, old);
            consultantDao.save(old);
        } else {
            throw new EntityNotExistException("id 为 " + id + " 的 Consultant不存在");
        }
    }

    @Override
    public Consultant getConsultant(String id) throws EntityNotExistException {
        Optional<Consultant> origin = consultantDao.findById(id);
        if (origin.isPresent()) {
            Consultant consultant = origin.get();
            int count = getConsultantQueueCount(consultant.getId());
            consultant.setBusy(count >= 5);
            return consultant;
        } else {
            throw new EntityNotExistException("id 为 " + id + " 的 Consultant不存在");
        }
    }

    @Override
    public Consultant getConsultantByPhoneNumber(String phoneNumber) throws EntityNotExistException {
        Consultant consultant = consultantDao.getConsultantByPhoneNumber(phoneNumber);
        if (consultant == null) {
            throw new EntityNotExistException("phoneNumber 为 " + phoneNumber + " 的 Consultant不存在");
        } else {
            int count = getConsultantQueueCount(consultant.getId());
            consultant.setBusy(count >= 5);
            return consultant;
        }
    }

    @Override
    public List<Consultant> getConsultants(List<String> ids) {
        if(ids != null)
            return consultantDao.findAllById(ids);
        else{
            return consultantDao.findAll();
        }
    }

    @Override
    public List<Consultant> getAllConsultants(){
        return consultantDao.findAll();
    }

    /**
     *
     * @param val String ("true" | "false")
     * @return List<Consultant>
     */
    @Override
    public List<Consultant> getAllConsultantByIsSupervisor(String val) {
        return consultantDao.findAllByIsSupervisor(val);
    }

    @Override
    public List<ConsultRecord> getConsultRecords(String consultantId) {
        return consultRecordDao.findAllByConsultantId(consultantId);
    }

    @Override
    public List<Supervisor> getBoundSupervisors(String consultantId) {
        List<SupervisorBind> supervisorBinds = supervisorBindDao.findAllByConsultantId(consultantId);
        Set<String> supervisorIds = new HashSet<>();
        for (SupervisorBind supervisorBind : supervisorBinds) {
            supervisorIds.add(supervisorBind.getSupervisorId());
        }

        return supervisorDao.findAllById(supervisorIds);
    }

    @Override
    public Boolean userAndConsultantHadRecords(String userId, String consultantId) {
        return consultRecordDao.findAllByUserIdAndConsultantId(userId, consultantId).size() > 0;
    }

    /**
     * 从 redis中获取当前咨询师的排队人数。
     * @param consultant_id
     * @return int 排队人数
     */
    private int getConsultantQueueCount(String consultant_id) {
        if (consultant_id == null) {
            return 0;
        }

        String redisKey = RedisKey.CONSULTANT_QUEUE.replace("{id}", consultant_id);
        Object value = redisTemplate.opsForValue().get(redisKey);
        if(value==null) return 0;
        String val = value.toString();
        if (val != null) {
            return Integer.parseInt(val);
        } else {
            return 0;
        }
    }
}
